/*********************************************************
*Copyright (c) 2009 Rob Groves. All Rights in All
*@des: seesion网络链接 用协程处理
*@name: seesion.hpp 
*@author: zhogn17hao
*@time: 2016-03-24
*********************************************************/

#ifndef __SESSION_HPP__
#define __SESSION_HPP__

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <boost/make_shared.hpp>
#include <boost/enable_shared_from_this.hpp>

#include "message.hpp"

class session:
    public boost::enable_shared_from_this<session>
{
public:
typedef boost::shared_ptr<session> session_ptr;
typedef boost::shared_ptr<message> message_ptr;
typedef boost::function<void(session_ptr&, message_ptr&) > CALLBACK_READ_MSG;

	session(boost::asio::io_service& ios): ios_(ios), socket_(ios) {
		//m_id = ++session::m_last_id;
	}

	void run(){
		state = 1;
		//创建一个协程用于 接收数据
		boost::asio::spawn(ios_, boost::bind(&session::do_read, this, _1));
	}
    
	void write(const char* pdata, int size){
		auto pmsg = boost::make_shared<message>(size + 1);
        pmsg->write(pdata, size);
        
		boost::asio::spawn(ios_, boost::bind(&session::do_write, this, pmsg, _1));
	}

	void close(){
		if (state){
			try {
				state = 0;
				socket_.shutdown(boost::asio::socket_base::shutdown_both);
				socket_.close();
			}
			catch (std::exception& e) {
				std::cout <<"close err: " << e.what() << std::endl;
			}
		}
	}

    boost::asio::ip::tcp::socket& socket(){
        return socket_;
    }

    void set_cb_read_msg(CALLBACK_READ_MSG cb_){
        cb_read_msg = cb_;
    }

private:
	//读数据
	void do_read(boost::asio::yield_context yield){
		unsigned short size_ = 0;
		while (state)
		{	
			size_ = 0;
			//先读取数据包长度
			boost::asio::async_read(socket_, boost::asio::buffer(&size_, sizeof(unsigned short)), yield);
			//准备数据区
            auto pmsg = boost::make_shared<message>(size_);
			//boost::shared_ptr<message> pmsg = boost::make_shared<message>(size_);
            /******************************************************************* 
             * --------len------- | --------------data----------- | ----crc--- |
             *
             ******************************************************************/
			pmsg->write((const char*)&size_, sizeof(unsigned short));
			//读取剩余数据
			boost::asio::async_read(socket_, 
				boost::asio::buffer(pmsg->get_write_data(), pmsg->get_write_size()),
				yield);
			//修改数据区 已写数据长度
			pmsg->add_write_size(size_ - sizeof(unsigned short));
			//通过callback 传递数据消息 
		    auto psession = this->shared_from_this();
            if (cb_read_msg){
                cb_read_msg(psession, pmsg);
            }
		}
	}

	//写数据
	void do_write(boost::shared_ptr<message> pmsg, boost::asio::yield_context yield){
		/*
		boost::coroutines::asymmetric_coroutine<int>::push_type sink( 
    		[&](boost::coroutines::asymmetric_coroutine<int>::pull_type& source){
        		
        	}
    	});
		sink(1);
		*/
		boost::system::error_code ec; 
		boost::asio::async_write(socket_, 
			boost::asio::buffer(pmsg->get_read_data(), pmsg->get_read_size()),
			yield[ec]);

		if (!ec){
			std::cout << "ID: " << m_id << "err:  "<< ec.message() << std::endl;
			//send_error_callback(m_id, pmsg, ec.message());
		}
	}
    
   

private:
    CALLBACK_READ_MSG cb_read_msg;
 //   std::function<void (std::shared_ptr<session>&, std::shared_ptr<message>&)> cb_read_msg;

	int state ; // 
	unsigned int m_id;
	boost::asio::io_service& ios_;
    boost::asio::ip::tcp::socket socket_;

    //static boost::detail::atomic_count m_last_id; //唯一标识符
}; 

#endif //__SESSION_HPP__
